# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: xguo

import datetime
import functools

import coin.exchange.bitflyer_v1.kr_rest.native_public_client as npc
from coin.exchange.base.kr_rest.futures_product import (
    gen_full_symbol,
    gen_short_symbol,
)
from coin.exchange.bitflyer_v1.kr_rest.constants import coin_list, fiat_list
from coin.exchange.bitflyer_v1.kr_rest.currency import (BitflyerCurrency, from_native_currency)

MONTH_ABBR = [
    "JAN",
    "FEB",
    "MAR",
    "APR",
    "MAY",
    "JUN",
    "JUL",
    "AUG",
    "SEP",
    "OCT",
    "NOV",
    "DEC",
]


def gen_bitflyer_date_string(date_str: str):
  '''Convert date string from forms like 20180310 to 10MAR2018'''
  date = datetime.datetime.strptime(date_str, '%Y%m%d')
  assert 2010 <= date.year <= 2030
  return date.strftime('%d%b%Y').upper()


# parse date strings in forms like `02MAR2018'.
def parse_bitflyer_date_string(date_str: str):
  date = datetime.datetime.strptime(date_str, '%d%b%Y')
  assert 2010 <= date.year <= 2030
  return date


def gen_bitflyer_native_symbol(base: BitflyerCurrency, quote: BitflyerCurrency, expiry: str):
  assert base.native_symbol in coin_list, base
  assert quote.native_symbol in fiat_list + ['BTC'], quote
  if expiry == 'IMMEDIATE':
    return '%s_%s' % (base.native_symbol, quote.native_symbol)
  elif expiry == 'PERPETUAL':
    assert base.native_symbol == 'BTC', base
    assert quote.native_symbol == 'JPY', quote
    return 'FX_BTC_JPY'
  else:
    return '%s%s%s' % (base.native_symbol, quote.native_symbol, gen_bitflyer_date_string(expiry))


def parse_bitflyer_native_symbol(native_symbol, current_datetime=None):
  current_datetime = current_datetime or datetime.datetime.now()
  res = {'native_symbol': native_symbol}
  if native_symbol == 'BTC_JPY':
    res['base'] = 'BTC'
    res['quote'] = 'JPY'
    res['type'] = 'spot'
    res['symbol'] = 'BTC-JPY'
    res['expiry'] = 'IMMEDIATE'
  elif native_symbol == 'BTC_USD':
    res['base'] = 'BTC'
    res['quote'] = 'USD'
    res['type'] = 'spot'
    res['symbol'] = 'BTC-USD'
    res['expiry'] = 'IMMEDIATE'
  elif native_symbol == 'BTC_EUR':
    res['base'] = 'BTC'
    res['quote'] = 'EUR'
    res['symbol'] = 'BTC-EUR'
    res['type'] = 'spot'
    res['expiry'] = 'IMMEDIATE'
  elif native_symbol == 'FX_BTC_JPY':
    res['base'] = 'BTC'
    res['quote'] = 'JPY'
    # This is not a future contract, but we treat it as something similar
    # to Bitflyer perpetual contract.
    res['type'] = 'futures'
    res['expiry'] = 'PERPETUAL'
    res['full_symbol'] = gen_full_symbol('BTC', 'JPY', 'PERPETUAL', 'Bitflyer', 'FX_BTC_JPY')
    res['short_symbol'] = gen_short_symbol('BTC', 'JPY', 'PERPETUAL')
  elif native_symbol == 'ETH_BTC':
    res['base'] = 'ETH'
    res['quote'] = 'BTC'
    res['symbol'] = 'ETH-BTC'
    res['type'] = 'spot'
    res['expiry'] = 'IMMEDIATE'
  elif native_symbol == 'ETH_JPY':
    res['base'] = 'ETH'
    res['quote'] = 'JPY'
    res['symbol'] = 'ETH-JPY'
    res['type'] = 'spot'
    res['expiry'] = 'IMMEDIATE'
  elif native_symbol == 'BCH_BTC':
    base = from_native_currency('BCH', current_datetime)
    quote = from_native_currency('BTC', current_datetime)
    res['base'] = base
    res['quote'] = quote
    res['symbol'] = '%s-%s' % (base, quote)
    res['type'] = 'spot'
    res['expiry'] = 'IMMEDIATE'
  elif native_symbol.startswith('BTCJPY'):
    expiry = parse_bitflyer_date_string(native_symbol[6:])
    res['base'] = 'BTC'
    res['quote'] = 'JPY'
    res['type'] = 'futures'
    res['expiry'] = expiry.strftime('%Y%m%d')
    res['full_symbol'] = gen_full_symbol('BTC', 'JPY', expiry, 'Bitflyer', 'FX_BTC_JPY')
    res['short_symbol'] = gen_short_symbol('BTC', 'JPY', expiry)
  else:
    raise ValueError('Unknown bitflyer symbol: %s' % native_symbol)
  return res


def fetch_exchange_product_info():
  client = npc.BitflyerNativePublicClient(timeout=10)
  return client.get_markets().msg


# Return value is cached.
@functools.lru_cache(maxsize=1)
def gen_bitflyer_product_list():
  product_info_list = fetch_exchange_product_info()
  assert product_info_list
  res = []
  for prod_info in product_info_list:
    native_symbol = prod_info['product_code']
    info = parse_bitflyer_native_symbol(native_symbol)
    res.append(info)
  assert res, 'Bitflyer product not found!'
  return res
